import * as dotenv from "dotenv";
dotenv.config();
import express from "express";
import pkg from "@prisma/client";
import morgan from "morgan";
import cors from "cors";
import { auth } from "express-oauth2-jwt-bearer";

// this is a middleware that will validate the access token sent by the client
const requireAuth = auth({
  audience: process.env.AUTH0_AUDIENCE,
  issuerBaseURL: process.env.AUTH0_ISSUER,
  tokenSigningAlg: "RS256",
});

const app = express();

app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(morgan("dev"));

const { PrismaClient } = pkg;
const prisma = new PrismaClient({
  log: ['query']
});

// this is a public endpoint because it doesn't have the requireAuth middleware
app.get("/ping", (req, res) => {
  res.send("pong");
});

// requireAuth middleware will validate the access token sent by the client and will return the user information within req.auth
app.get("/queryMoiveList", requireAuth, async (req, res) => {
  const pageSize = parseInt(req.query.pageSize) || 10;
  const current = parseInt(req.query.current) || 1;
  const keyword = req.query.keyword || '';

  const auth0Id = req.auth.payload.sub;

  try {
    let queryConditions = {};

    if (keyword !== '') {
      // 对 title 和 genre.name 进行模糊匹配
      queryConditions = {
        OR: [
          {
            title: {
              contains: keyword,
            },
          },
          {
            genre: {
              some: {
                name: {
                  contains: keyword,
                },
              },
            },
          },
        ],
      };
    }

    // 查询总电影数，考虑关键词筛选
    const total = await prisma.movie.count({
      where: queryConditions,
    });

    // 查询当前页的电影数据，考虑关键词筛选
    const movies = await prisma.movie.findMany({
      where: queryConditions,
      skip: (current - 1) * pageSize,
      take: pageSize,
      select: {
        id: true,
        title: true,
        image: true,
        description: true,
        rating: {
          where: {
            user: {
              auth0Id: auth0Id,
            },
          },
          select: {
            id: true,
            score: true,
          },
        },
        genre: {
          select: {
            name: true,
          },
        },
      },
    });

    const processData = movies.map((movie) => ({
      ...movie,
      genre: movie.genre.map((g) => g.name),
      rating: movie.rating.length > 0 ? movie.rating[0].score : null,
      ratingId: movie.rating.length > 0 ? movie.rating[0].id : null
    }));

    res.json({
      total: total,
      pageSize: pageSize,
      current: current,
      result: processData,
    });
  } catch (error) {
    res.status(500).send(error.message);
  }
});

app.post("/updateMovie", requireAuth, async (req, res) => {
  const { id, title, description, rating, ratingId } = req.body;

  if (!id) {
    return res.status(400).send("Movie ID is required");
  }
  try {
    // 更新电影信息
    await prisma.movie.update({
      where: { id: id },
      data: {
        title: title,
        description: description,
        // 根据您的数据库结构调整对评分的更新
        rating: {
          update: {
            where: { id: ratingId },
            data: { score: rating }
          }
        }
      }
    });

    res.json({
      msg: 'Update successful!'
    });
  } catch (error) {
    res.status(500).send(error.message);
  }
});

app.delete("/deleteMovie", requireAuth, async (req, res) => {
  const { movieId } = req.body;

  if (!movieId) {
    return res.status(400).send("Movie ID is required");
  }

  try {
    // 开始一个事务
    await prisma.$transaction(async (prisma) => {
      // 首先删除与电影相关的所有评分
      await prisma.rating.deleteMany({
        where: { movieId: movieId }
      });

      // 然后删除电影
      await prisma.movie.delete({
        where: { id: movieId }
      });
    });

    res.send("Movie and associated ratings deleted successfully");
  } catch (error) {
    res.status(500).send(error.message);
  }
});

// 创建接口以根据 rating ID 更新 score
app.post("/updateRating", requireAuth, async (req, res) => {
  const { ratingId, newScore } = req.body;
  if (!ratingId || newScore === undefined) {
    console.log(ratingId, 'ratingId');
    console.log(newScore, 'newScore');
    return res.status(400).send("Both ratingId and newScore are required");
  }

  try {
    const updatedRating = await prisma.rating.update({
      where: {
        id: ratingId,
      },
      data: {
        score: newScore,
      },
    });

    res.json({
      message: 'Rating updated successfully',
      updatedRating,
    });
  } catch (error) {
    res.status(500).send(error.message);
  }
});

// get Profile information of authenticated user
app.get("/me", requireAuth, async (req, res) => {
  const auth0Id = req.auth.payload.sub;

  const user = await prisma.user.findUnique({
    where: {
      auth0Id,
    },
  });

  res.json(user);
});

// this endpoint is used by the client to verify the user status and to make sure the user is registered in our database once they signup with Auth0
// if not registered in our database we will create it.
// if the user is already registered we will return the user information
app.post("/verify-user", requireAuth, async (req, res) => {
  const auth0Id = req.auth.payload.sub;
  const email = req.auth.payload[`${process.env.AUTH0_AUDIENCE}/email`];
  const name = req.auth.payload[`${process.env.AUTH0_AUDIENCE}/name`];
  console.log(auth0Id, "auth0Id");
  console.log(email, "email");
  console.log(name, "name");
  const user = await prisma.user.findUnique({
    where: {
      auth0Id,
    },
  });

  if (user) {
    console.log(user, "history User");
    res.json(user);
  } else {
    const newUser = await prisma.user.create({
      data: {
        email,
        auth0Id,
        name,
      },
    });
    console.log(newUser, "new User");
    res.json(newUser);
  }
});

app.listen(8000, () => {
  console.log("Server running on http://localhost:8000 🎉 🚀");
});
